package com.common.base.app.viewmodel

import androidx.lifecycle.*
import com.common.base.R
import com.common.base.app.extras.getShowMsg
import com.common.base.app.extras.otherwise
import com.common.base.app.extras.yes
import com.common.base.utils.AppUtils.getString
import com.common.base.utils.ToastUtils
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import rxhttp.wrapper.OkHttpCompat
import rxhttp.wrapper.utils.LogUtil

//类型别名
typealias LaunchBlock = suspend CoroutineScope.() -> Unit

typealias EmitBlock<T> = suspend LiveDataScope<T>.() -> T

typealias Cancel = (e: Exception) -> Unit

abstract class BaseViewModel : ViewModel(), LifecycleObserver {

    val mStateLiveData = MutableLiveData<StateActionEvent>()//通用事件模型驱动(如：显示对话框、取消对话框、错误提示)

    //统一失败处理
    val mFailureLiveData = MutableLiveData<Boolean>()

    fun showErrorToast(toast: String = getString(R.string.network_framework_data_error)) {
        ToastUtils.showToast(toast)
    }

    fun launch(cancel: Cancel? = null, block: LaunchBlock) {//使用协程封装统一的网络请求处理
        viewModelScope.launch {
            //ViewModel自带的viewModelScope.launch,会在页面销毁的时候自动取消请求,有效封装内存泄露
            try {
                mStateLiveData.value = LoadState
                block()
                mStateLiveData.value = SuccessState
            } catch (e: Exception) {
                when (e) {
                    is CancellationException -> cancel?.invoke(e)
                    else -> (cancel != null).yes {
                        mFailureLiveData.postValue(true)
                        cancel?.invoke(e)
                    }.otherwise {
////                        mStateLiveData.value = ErrorState(e.message)
//                        mStateLiveData.value = ErrorState(matchErrorString(e))
                        mStateLiveData.value = ErrorState(e.getShowMsg())
                    }
                }
            }
        }
    }

    fun <T> emit(cancel: Cancel? = null, block: EmitBlock<T>): LiveData<T> = liveData {
        try {
            mStateLiveData.value = LoadState
            emit(block())
            mStateLiveData.value = SuccessState
        } catch (e: Exception) {
            LogUtil.log("RxHttp: <------ ${e.message}------>")
            when (e) {
                is CancellationException -> cancel?.invoke(e)
                else -> (cancel != null).yes {
                    mFailureLiveData.postValue(true)
                    cancel?.invoke(e)
                }.otherwise {
                    mStateLiveData.value = ErrorState(e.message)
//                    mStateLiveData.value = ErrorState(matchErrorString(e))
                    mStateLiveData.value = ErrorState(e.getShowMsg())
                }
            }

//            when (e) {
//                is CancellationException -> cancel?.invoke(e)
//                else -> (cancel != null).yes {
//                    mFailureLiveData.postValue(true)
//                    //修改网络异常错误信息
//                    when (e) {
//                        is UnknownHostException,is HttpStatusCodeException,is SSLHandshakeException,is SocketException,
//                        is NetworkErrorException, is SocketTimeoutException -> cancel?.invoke(NetworkErrorException(getString(R.string.network_framework_data_error)))
//                        else->cancel?.invoke(e)
//                    }
//                }.otherwise {
//                    when (e) {
//                        is HttpStatusCodeException -> mStateLiveData.value = ErrorStateAnMsg(e.statusCode, getString(R.string.network_framework_data_error))
//                        is UnknownHostException, is NetworkErrorException -> mStateLiveData.value = ErrorState(getString(R.string.network_framework_data_error))
//                        else-> mStateLiveData.value = ErrorState(e.message)
//                    }
//                }
//            }
        }
    }


    fun <T> emitCommon(message: String? = null, block: EmitBlock<T>): LiveData<T> = emit({ ToastUtils.showToast(message ?: it.message) }, block)
}